package de.uni_mannheim.informatik.ai.dame_ai.dame.domain;

import java.util.ArrayList;

public class GameLogic {

	/**
	 * Method calculates all Jumpmoves
	 * @param currentStatus Current game status
	 * @param position position of the selected piece
	 * @return Possible jump moves
	 */
	public static Move[] getPossibleJumpMoves(Piece[] currentStatus, int position) {
		ArrayList<Move> possibleMoves = new ArrayList<Move>();
		Move[] allPossibleMoves = getPossibleMoves(currentStatus, position);
		for (Move move : allPossibleMoves) {
			if (move.isJump)
				possibleMoves.add(move);
		}
		return possibleMoves.toArray(new Move[possibleMoves.size()]);
	}
	/**
	 * Returns if position is on board
	 * @param position To be tested position
	 * @return True if position exists on board
	 */
	public static boolean inBoard(int position) {
		if (position > 0 && position < 64)
			return true;
		else
			return false;
	}
	/**
	 * Method returns if selected piece is opponent
	 * @param selectedPiece Selected piece
	 * @param otherPiece to be tested piece
	 * @return True is other piece is an opponent
	 */
	public static boolean isOpponent(int selectedPiece, int otherPiece) {
		if (selectedPiece == Piece.EMPTY)
			return false;
		if (selectedPiece == Piece.BLACK || selectedPiece == Piece.BLACKDAME) {
			if (otherPiece == Piece.WHITE || otherPiece == Piece.WHITEDAME)
				return true;
			else
				return false;
		} else {
			if (otherPiece == Piece.BLACK || otherPiece == Piece.BLACKDAME)
				return true;
			else
				return false;
		}
	}
	/**
	 * 
	 * @param currentPlayer Current Player
	 * @return Returns all possible moves for player
	 */
	public static Move[] getAllPossibleMoves(Piece[] currentStatus,Player player){
		ArrayList<Move> possibleMoves = new ArrayList<Move>();
		boolean jumpMoveRequired = false;
		for(int i = 0; i< Board.BOARDSQUARES;i++){
			if((player.color == Player.BLACK && isBlack(currentStatus[i].getType()))||(player.color == Player.WHITE && isWhite(currentStatus[i].getType()))){
				System.out.println("Getting moves.................");
				Move[] temp = getPossibleMoves(currentStatus, i);
				for(Move x : temp){
					possibleMoves.add(x);
				}
			}
		}
		System.out.println("All Possible mOves: "+possibleMoves.size());
		return possibleMoves.toArray(new Move[possibleMoves.size()]);
	}
	private static void addMoves(ArrayList<Move> existingMoves,Move[] newMoves){
		for(Move temp : newMoves){
			existingMoves.add(temp);
		}
	}
	public static Move[] getAllPossibleJumpMoves(Piece[] currentStatus,Player player){
		ArrayList<Move> possibleMoves = new ArrayList<Move>();
		addMoves(possibleMoves, getAllPossibleMoves(currentStatus,player));
		System.out.println("Sizeof Posible Moves" +possibleMoves.size());
		ArrayList<Move> rmvList = new ArrayList<Move>();
		for(Move checkMove : possibleMoves){
			if(!checkMove.isJump) rmvList.add(checkMove);
		}
		possibleMoves.removeAll(rmvList);
		rmvList.clear();
		return possibleMoves.toArray(new Move[possibleMoves.size()]);

	}
	public static Move[] getAllPossibleJumpMoves(Move[] moves){
		ArrayList<Move> possibleMoves = new ArrayList<Move>();
		addMoves(possibleMoves, moves);
		ArrayList<Move> rmvList = new ArrayList<Move>();
		for(Move checkMove : possibleMoves){
			if(!checkMove.isJump) rmvList.add(checkMove);
		}
		possibleMoves.removeAll(rmvList);
		rmvList.clear();
		return possibleMoves.toArray(new Move[possibleMoves.size()]);

	}
	public static boolean isBlack(int type){
		if(type == Piece.BLACK || type == Piece.BLACKDAME) return true; 
		else return false;
	}
	public static boolean isWhite(int type){
		if(type == Piece.WHITE || type == Piece.WHITEDAME) return true; else return false;
	}
	private static Move[] getPossibleDameMoves(Piece[] pieces, int position){
		ArrayList<Move> possibleMoves = new ArrayList<Move>();
		ArrayList<Move> jumpMoves = new ArrayList<Move>();
		boolean isJump = false;
		assert(pieces[position].getType()==Piece.BLACKDAME||pieces[position].getType()==Piece.WHITEDAME);
		possibleMoves.addAll(getPossibleDirectionalDameMoves(pieces,position,-9,7));
		possibleMoves.addAll(getPossibleDirectionalDameMoves(pieces,position,-7,0));
		possibleMoves.addAll(getPossibleDirectionalDameMoves(pieces,position,7,7));
		possibleMoves.addAll(getPossibleDirectionalDameMoves(pieces,position,9,0));
 		for(Move move : possibleMoves){
 			if(move.isJump()){
 				jumpMoves.add(move);
 			}
 		}
 		if(jumpMoves.size()>0){
 			possibleMoves = jumpMoves;
 		}
		return possibleMoves.toArray(new Move[possibleMoves.size()]);
	}
	private static boolean isDame(Piece[] pieces, int position){
		if(pieces[position].getType()==Piece.BLACKDAME || pieces[position].getType()==Piece.WHITEDAME){
			return true;
		} else return false;
	}
	private static ArrayList<Move> getPossibleDirectionalDameMoves(Piece[] pieces, int position, int increaseRate, int modCheck){
		
		ArrayList<Move> possibleMoves = new ArrayList<Move>();
		int checkPosition = position +increaseRate;
		int checkCheckPosition= checkPosition +increaseRate;;
		int checkType;
		int counter=0;
		int checkCheckType;
		int ownType = pieces[position].getType();
		while(inBoard(checkPosition) && checkPosition % 8 != modCheck){
			counter++;
			System.out.println("Counter: "+counter+" CheckPosition: "+checkPosition);
			assert(counter<9);
			checkType = pieces[checkPosition].getType();
			if(checkType == Piece.EMPTY){
				possibleMoves.add(new Move(position,checkPosition,false));
				checkPosition = checkCheckPosition;
				checkCheckPosition+=increaseRate;
			} else if (isOpponent(ownType,checkType)){
				if(inBoard(checkCheckPosition) && checkCheckPosition % 8 != modCheck){
					checkCheckType = pieces[checkCheckPosition].getType();
					if(isOpponent(ownType,checkCheckType)){
						break;
					} else if(checkCheckType == Piece.EMPTY){
						possibleMoves.add(new Move(position,checkCheckPosition,true));
					}
				} else {
					break;
				}
				checkPosition = checkCheckPosition;
				checkCheckPosition+=increaseRate;
			} else {
				break;
			}
		}
		
		return possibleMoves;
	}
	
	/**
	 * Gets all Possible moves for selected piece
	 * @param currentStatus game status of the board
	 * @param position The selected Piece
	 * @return Return possible moves for selected piece
	 */
	public static Move[] getPossibleMoves(Piece[] currentStatus, int position) {
		if(isDame(currentStatus,position)){
			return getPossibleDameMoves(currentStatus,position);
		}
		ArrayList<Move> possibleMoves = new ArrayList<Move>();
		int type = currentStatus[position].getType();
		if (type == Piece.EMPTY)
			return possibleMoves.toArray(new Move[possibleMoves.size()]);
		if (type != Piece.WHITE) {
			int checkposition = position - 9;
			if (inBoard(checkposition)) {
				int checkType = currentStatus[checkposition].getType();
				System.out.println("Position: " + position + " Checkposition: "
						+ checkposition + " mod8: " + position % 8
						+ " fieldEmpty: " + (checkType == Piece.EMPTY));
				if (position % 8 != 0) {
					if (checkType == Piece.EMPTY) {
						possibleMoves.add(new Move(position, checkposition));
					} else if (isOpponent(type, checkType)) {
						int secondCheckPosition = checkposition - 9;
						if (checkposition % 8 != 0
								&& inBoard(secondCheckPosition)
								&& currentStatus[secondCheckPosition].getType() == Piece.EMPTY) {
							possibleMoves.add(new Move(position,
									secondCheckPosition, true));
						}
					}
				}
			}
			checkposition = position - 7;
			if (inBoard(checkposition)) {
				int checkType = currentStatus[checkposition].getType();
				System.out.println("Position: " + position + " Checkposition: "
						+ checkposition + " mod8: " + checkposition % 8
						+ " fieldEmpty: " + (checkType == Piece.EMPTY));
				if (position % 8 != 7) {
					if (checkType == Piece.EMPTY) {
						possibleMoves.add(new Move(position, checkposition));
					} else if (isOpponent(type, checkType)) {
						int secondCheckPosition = checkposition - 7;
						if (checkposition % 8 != 7
								&& inBoard(secondCheckPosition)
								&& currentStatus[secondCheckPosition].getType() == Piece.EMPTY) {
							possibleMoves.add(new Move(position,
									secondCheckPosition, true));
						}
					}
				}
			}
		}
		if (type != Piece.BLACK) {
			int checkposition = position + 9;
			if (inBoard(checkposition)) {
				int checkType = currentStatus[checkposition].getType();
				System.out.println("Position: " + position + " Checkposition: "
						+ checkposition + " mod8: " + checkposition % 8
						+ " fieldEmpty: " + (checkType == Piece.EMPTY));
				if (position % 8 != 7 ) {
					if (checkType == Piece.EMPTY) {
						possibleMoves.add(new Move(position, checkposition));
					} else if (isOpponent(type, checkType)) {
						int secondCheckPosition = checkposition + 9;
						if (checkposition % 8 != 7
								&& inBoard(secondCheckPosition)
								&& currentStatus[secondCheckPosition].getType() == Piece.EMPTY) {
							possibleMoves.add(new Move(position,
									secondCheckPosition, true));
						}
					}
				}
			}
			checkposition = position + 7;
			if (inBoard(checkposition)) {
				int checkType = currentStatus[checkposition].getType();
				System.out.println("Position: " + position + " Checkposition: "
						+ checkposition + " mod8: " + checkposition % 8
						+ " fieldEmpty: " + (checkType == Piece.EMPTY));
				if (position % 8 != 0 ) {
					if (checkType == Piece.EMPTY) {
						possibleMoves.add(new Move(position, checkposition));
					} else if (isOpponent(type, checkType)) {
						int secondCheckPosition = checkposition + 7;
						if (checkposition % 8 != 0
								&& inBoard(secondCheckPosition)
								&& currentStatus[secondCheckPosition].getType() == Piece.EMPTY) {
							possibleMoves.add(new Move(position,
									secondCheckPosition, true));
						}
					}
				}
			}
		}
		return possibleMoves.toArray(new Move[possibleMoves.size()]);
	}
	/**
	 * Deselects all highlighted squares
	 * @param squares The board squares
	 */
	public static void deselect(Square[] squares) {
		for (int i = 0; i < squares.length; i++) {
			squares[i].setHighlighted(false);
		}
	}
	/**
	 * Checks if move is possible by given game status
	 * @param currentStatus The current Game status
	 * @param move The selected Move
	 * @return Returns if move is possible
	 */
	public static boolean isPossible(Piece[] currentStatus, Move move) {
		Move[] possibleMoves = getPossibleMoves(currentStatus, move.selectedPosition);
		System.out.println("Checking possible moves count: "
				+ possibleMoves.length);
		for (Move checkMove : possibleMoves) {
			if (checkMove.equals(move))
				return true;
		}
		System.out.println("move not possible");
		return false;
	}
	private static Move isJumpMove(Piece[] pieces,Move move){
		boolean isSouth=false;
		boolean isWest = false;
		int checkPosition = move.getFromPos();
		int power = Math.abs(move.selectedPosition / 8 - move.targetPosition / 8);
		if (power == 1) {
			System.out.println("Move is NOT a jump Move");
			return move;
		} else if (power >= 2) {
			int distance = move.selectedPosition - move.targetPosition;
			if(distance>0)isSouth= false; else isSouth = true; 
			if(move.selectedPosition % 8 < move.targetPosition % 8 ) isWest = false; else isWest = true;
			int increaseRate;
			if(isWest && isSouth){
				increaseRate = 7;
			} else if (!isWest && isSouth){
				increaseRate = 9;
			} else if (!isWest && !isSouth ){
				increaseRate = -7;
			} else {
				increaseRate = -9;
			}
			checkPosition += increaseRate;
			
			if(!isSouth){
				while(checkPosition>move.targetPosition){
					assert(inBoard(checkPosition));
					if(pieces[checkPosition].getType()!=Piece.EMPTY){
						move.setJump(true);
						move.setKillPosition(checkPosition);
						System.out.println("Move is a jump Move");
						return move;

					}
					checkPosition += increaseRate;
				}			
			} else {
				while(checkPosition<move.targetPosition){
					assert(inBoard(checkPosition));
					if(!inBoard(checkPosition))System.out.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxxxxxß\n\n" +
							"xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
					if(pieces[checkPosition].getType()!=Piece.EMPTY){
						move.setJump(true);
						move.setKillPosition(checkPosition);
						System.out.println("Move is a jump Move");
						return move;

					}
					checkPosition += increaseRate;
				}	
			}
		}
		
		return move;
	}
	/**
	 * 
	 * @param move The move to be executed
	 * @param currentStatus The current Game status
	 * @param board The board of the game
	 * @param currentPlayer The current player
	 * @return Returns the new current Player
	 */
	public static int executeMove(Move move, Board board,
			int currentPlayer) {
		move = isJumpMove(board.getPiecesStatus(),move);
		Piece[] currentStatus = board.getPiecesStatus();
		//int currentPosition = move.selectedPosition;
		int distanceAbs = move.selectedPosition - move.targetPosition;
		int power = Math.abs(move.selectedPosition / 8 - move.targetPosition / 8);
		int direction = (move.selectedPosition % 8) - (move.targetPosition % 8);
		if (!move.isJump()) {
			currentStatus[move.targetPosition].setType(currentStatus[move.selectedPosition]
					.getType());
			currentStatus[move.selectedPosition].setType(Piece.EMPTY);
			deselect(board.getBoard());
			if (currentPlayer == 0)
				currentPlayer = 1;
			else
				currentPlayer = 0;
		} else if (move.isJump()) {
			currentStatus[move.targetPosition].setType(currentStatus[move.selectedPosition]
					.getType());
			currentStatus[move.selectedPosition].setType(Piece.EMPTY);
			currentStatus[move.killPosition].setType(Piece.EMPTY);
			if (currentStatus[move.targetPosition].getType() == Piece.BLACK
					&& move.targetPosition < Board.WHITEHOME) {
				currentStatus[move.targetPosition].setType(Piece.BLACKDAME);
			} else if (currentStatus[move.targetPosition].getType() == Piece.WHITE
					&& move.targetPosition > Board.BLACKHOME) {
				currentStatus[move.targetPosition].setType(Piece.WHITEDAME);
			}
			Move[] possibleNewMoves = getPossibleJumpMoves(currentStatus,
					move.getToPos());
			if (possibleNewMoves.length == 0) {
				if (currentPlayer == 0)
					currentPlayer = 1;
				else
					currentPlayer = 0;
				deselect(board.getBoard());
			} else {
				deselect(board.getBoard());
				selectPiece(possibleNewMoves, board.getBoard());
			}
		}
		if (currentStatus[move.targetPosition].getType() == Piece.BLACK
				&& move.targetPosition < Board.WHITEHOME) {
			currentStatus[move.targetPosition].setType(Piece.BLACKDAME);
		} else if (currentStatus[move.targetPosition].getType() == Piece.WHITE
				&& move.targetPosition > Board.BLACKHOME) {
			currentStatus[move.targetPosition].setType(Piece.WHITEDAME);
		}
		return currentPlayer;

	}

	public static Square[] highlightSquares(Piece[] currentStatus,
			Square[] currentBoard, int position) {
		Move[] possibleMoves = getPossibleMoves(currentStatus, position);

		return currentBoard;
	}
	/**
	 * 
	 * @param possibleMoves The possible moves of a given selected piece
	 * @param currentBoard The current Board to be changed
	 * @return True if there are possible moves
	 */
	public static boolean selectPiece(Move[] possibleMoves, Square[] currentBoard) {
		if (possibleMoves.length > 0) {
			for (int i = 0; i < possibleMoves.length; i++) {
				currentBoard[possibleMoves[i].targetPosition].setHighlighted(true);
			}
			return true;
		} else
			return false;
	}
}
